package cz.cuni.amis.episodic.dybanem;

import static cz.cuni.amis.episodic.bayes.utils.JSmileUtil.dbnNodeId;

import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;

import smile.Network;
import smile.learning.DataMatch;
import smile.learning.DataSet;
import smile.learning.EM;
import au.com.bytecode.opencsv.CSVReader;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

/**
 * Hello world!
 * 
 */
public class App {

	/**
	 * Loads data from CSV file to unrolled DBN created in Genie. Follows
	 * Genie's naming conventions.
	 * 
	 * @param dbn
	 * @param csvFileName
	 * @throws IOException
	 */
	public static void loadDBNevidence(Network dbn, String csvFileName)
			throws IOException {

		// read data from CSV
		CSVReader reader = new CSVReader(new FileReader(csvFileName));
		String[] header = reader.readNext();

		String[] nextLine;
		int lineNum = 0;
		while ((nextLine = reader.readNext()) != null) {
			for (int i = 0; i < nextLine.length; i++) {
				String nodeName = dbnNodeId(header[i], lineNum);

				dbn.setEvidence(nodeName, nextLine[i]);
			}
			lineNum++;
		}
	}

	public static void readDataSetFromCsv(String csvFileName) throws IOException {
		int run = 0;
		// number of time steps in one sequence
		final int N = 10;

		DataSet ds = new DataSet();

		// read data from CSV
		CSVReader reader = new CSVReader(new FileReader(csvFileName));
		String[] header = reader.readNext();

		// variables will be in the same order as in the header
		for (int i = 0; i < N; i++) {
			for (String var : header) {
				ds.addIntVariable(dbnNodeId(var, i));
			}
		}

		// create new record ... that is sequence of examples in DS
		ds.addEmptyRecord();

		String[] nextLine;
		int lineNum = 0;
		while ((nextLine = reader.readNext()) != null) {
			for (int i = 0; i < nextLine.length; i++) {
				String nodeName = dbnNodeId(header[i], lineNum);

				// read data to DS
				ds.setInt((lineNum + 1) * i, run, Integer.valueOf(nextLine[i]));
			}
			lineNum++;
		}

	}

	/**
	 * Reads values from DBN into table.
	 * 
	 * @param net
	 * @param targetNode
	 * @param steps
	 * @return
	 */
	public static Table<String, Integer, Double> readTemporalValue(Network net,
			String targetNode, int steps) {
		String[] outcomeIds = net.getOutcomeIds(targetNode);
		Table<String, Integer, Double> table = HashBasedTable.create();

		for (int i = 0; i < steps; i++) {
			String nodeId = dbnNodeId(targetNode, i);

			double[] vals = net.getNodeValue(nodeId);
			int j = 0;
			for (String id : outcomeIds) {
				table.put(id, i, vals[j]);
				j++;
			}
		}
		return table;
	}

	public static void main(String[] args) throws IOException {
		Network net = new Network();
		net.readFile("../CognitiveLoadDBN-unrolled.xdsl");
		loadDBNevidence(net, "cognitiveLoadEvidence.csv");
		net.updateBeliefs();
		// System.out.println(readTemporalValue(net, "CognitiveLoad",
		// 10).toString());
		GoogleUtils.printTable(readTemporalValue(net, "CognitiveLoad", 10), System.out, "\t");
		//learn(net);
	}

	public static void learn(Network net, Table<String, Integer, Double> table) {
		DataSet ds = new DataSet();
		ds.addIntVariable("Var1");
		ds.getVariableId(0);
		ds.setStateNames(0, new String[] {"Low", "Medium", "High"});
		ds.getStateNames(0);
		ds.addEmptyRecord();
		ds.setInt(0, 0, 1);
		ds.getVariableId(1);
		
		DataMatch[] match = ds.matchNetwork(net); //-> do i need this line? what for? It appears me as void, not creating a DataMatch[]...
		final EM em = new EM();
		em.setEqSampleSize(2); //-> learning algorithm parameter, if i'm wright
		em.setRandomizeParameters(true); //-> Not sure about this, it means that randomize the values of the nodes that are not informed in the txt?
		em.learn(ds, net, match);
	}
}
